#ifndef THREAD_WRAPPER_H_INCLUDED
#define THREAD_WRAPPER_H_INCLUDED

#include <iostream>
#include <stdexcept>
#include <pthread.h>
#include <sys/types.h>

#include "Utils.h"
#include "Debug.h"

using namespace std;

#define THREAD_IDLE     0
#define THREAD_RUNNING  1
#define THREAD_DEAD     2
#define THREAD_GCR      3


/**
 *\brief An wrapper file for posix thread
 *
 *i am planning to use this class as a base for the Layer class,
 *Level class, Renderer class, Update_Subsys class
 */

class Thread_Wrapper
{
public:
    /**
     *the default consturctor sets currentState to THREAD_IDLE
     */
    Thread_Wrapper();
    virtual~Thread_Wrapper(){};

    bool operator == (const Thread_Wrapper& obj) const;
    bool operator != (const Thread_Wrapper& obj) const;

    /**
    * \brief creates a thread
    * \param thread_join indicates join() will be called or not
    *
    * creates a posix thread that calls Thread_Wrapper::threadFunction
    * if argument thread_join is false detaches the thread
    */
    bool  start(bool thread_join = true);

    ///sets the currentState variable
    bool  setThreadState(int state);

    ///returns the currentState variable
    int   getThreadState();

    ///pthread_cancel(threadID)
    void  terminate();

    ///pthread_exit((void**)0)
    void  exit();

    ///return (int)threadID;
    int   self();

    ///pthread_join(threadID, (void**)&status)
    int     join(void);

protected:

    ///The constructor to create Thread_Wrapper from another
    Thread_Wrapper(const Thread_Wrapper&) {};

    ///Overloaded = operator
    Thread_Wrapper& operator=(const Thread_Wrapper&) { return *this; }

    /**
     *\brief Virtual function to be overloaded in derived class
     *
     *This function contains the code that will run in the thread
     */
    virtual void execute()=0;

    /**
    * \brief calls run
    * \param pointer to a void*
    *
    * Typecasts argument to Thread_Wrapper* and calls it run method
    */
    static  void* threadFunction(void *pt);

    ///Calls execute
    void    run();

    ///Calls pthread_detach(threadID)
    void    detach(void);

    /**
     * \brief calls sched_yield()
     *
     *Tries to suspend current thread so other high priority thread can continue
     */
    void    yield(void)  const;

    ///Sets priority
    bool    setPriority(int priority);

    ///Gets priority
    int     getPriority();

private:

    ///contins the thread handle
    pthread_t    threadID;

    ///contains current state
    int          currentState;

};


#endif // THREAD_WRAPPER_H_INCLUDED
